/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package server;


import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.xbill.DNS.Header;


/**
 * Response class, handling request, request object with headers is passed to constructor
 * @author Peewhy
 */
public class Response {
    public static final String CRLF = "\r\n";

    public Request request;    
    public ResponseHeader header;
    public Server server;
    public ByteArrayOutputStream body;
    
    /**
     * Initiliazes Response keeping request header inside
     * !! Make defensive copy of request.
     * @param server
     * @param request
     */
    public Response(Server server, Request request) {
        this.server = server;
        this.request = request;
        this.header = new ResponseHeader();
        this.body = new ByteArrayOutputStream();
    }
    
    /**
     * Obtains body of respond
     * @return stream, in which we can write output, it will be put as body part
     */
    public OutputStream getBodyStream(){
        return body;
    }
    
    public ResponseHeader getHeader() {
    	return header;
    }
    
    // Copy requested file into the socket's output stream.
    private static void copy (InputStream fis, OutputStream os) throws IOException {        
        byte[] buffer = new byte[1024*1000];
        int bytes = 0;                
        while((bytes = fis.read(buffer)) != -1 )
            os.write(buffer, 0, bytes);
    }

    // Only request methods: POST, GET and HEAD are supported
    private boolean requestTypeOK() {
        String rtype = request.header.getMethod();
        if (rtype.equals("GET") || rtype.equals("POST") || rtype.equals("HEAD")) {
            // Atpazistame
            return true;
        }
        else {
            header.setStatus(501, "server does not support " + rtype);
            return false;
        }
    }    
    
    public void show (DataOutputStream stream) throws IOException {
       // Set size of body
       Logger.getLogger(Server.LOG).log(Level.INFO, "Response to client");
       header.setContentLength(body.size());
       stream.writeBytes(header.getHeaders());
       stream.writeBytes(CRLF);     
       body.write("\n".getBytes());
       stream.write(body.toByteArray());       
       //stream.writeBytes(body.toString());
    }
    
    // Format link for filename
    private byte[] getLink(String filename) {
        return ("<a href=\"" + filename + "\">" + filename + "</a><br>\n").getBytes();
    }
    
    /**
     * Returns path of first index file found in folder
     * @param folder path for searching index file
     * @return founded path, empty if no index file found
     */
    public String getExistingIndex(String folder) {
        Iterator<String> i = server.config.getIndexIterator();
        while (i.hasNext()) {
            String temp = folder + i.next(); 
            try {
                FileInputStream fis = new FileInputStream(temp);
                fis.close();
                return temp;
            }
            catch (FileNotFoundException e) { } // Expected   
            catch (IOException er) { } // Expected
        }
        return "";
    }
    
    private boolean isFileName(String filename) {
        //return filename.contains(".");
        File f = new File(filename);
        return f.list() == null ? true : false;
    }
    
    
    public void handle() throws IOException, Exception {                        
       if (requestTypeOK()) { // Request type supported 
           
    	   // Serve as dynamic script
    	   boolean handled = server.getRouter().serve(request, this);
    	   
    	   // Serve as file
    	   if (!handled) {
    		
    	   
           // Obtains absolute address of file
           String filename = server.getConfig().getRoot();
           filename += request.header.getUrlQuery();               
           String nfilename = filename;
           
           String suffix = request.header.getUrlQuery();           
           
           // Is file not specified, if not, use default       
           if (!isFileName(filename)) {
                nfilename = getExistingIndex(filename);
           }           

            // No file specified, list directory
            System.out.println(nfilename);
            if (nfilename.equals("/") || (nfilename.equals(""))) {
                InputStream is = new FileInputStream(server.getConfig().getRoot() + "/list.html");
                copy (is, this.getBodyStream());
                is.close();

                File index = new File(filename);              
                String[] fileList = index.list();

                if (fileList != null) {
                    for (String el: fileList) {
                         this.getBodyStream().write(getLink(el));
                    }
                }
                else {                            
                    header.setStatus(404, request.header.getUrl());                
                }
            }
            else {
            // File specified, open a file
               // Extension ? 
            	
            	
               int poz = filename.lastIndexOf(".");
               if (poz != -1) {
                   String extension = filename.substring(poz);
                   String ctype = server.getContentType(extension);
                   header.setContentType(ctype);
               }
                       
                filename = nfilename;
                try {                    
                    FileInputStream fis = new FileInputStream(filename);
                    copy (fis, this.getBodyStream());                                        
                    fis.close();
                    header.setStatus(200);

                } catch (FileNotFoundException e) {
                	Logger.getLogger(Server.LOG).severe("File not found");
                    header.setStatus(404, request.header.getUrl());
                    
                    InputStream is = new FileInputStream(server.getConfig().getRoot() + "/error.html");
                    copy (is, this.getBodyStream());
                    is.close();                    
                }        
             }
            
            
    	   }
    	   // Serve as file
       } // RequestType is OK
       else { 
           header.setStatus(501, request.header.getMethod());
       }     
       

    } // handle()
}
